/*****************************************************************************
 *   Copyright 2005 Tim A Wang
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 ****************************************************************************/
package com.jb.web.bean.custom;

import com.jb.util.Meter;
import com.jb.web.application.configuration.Config;
import com.jb.web.context.WebContext;
import com.jb.web.session.SessionUser;

import java.io.File;
import java.io.FileFilter;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


public class FileUploadHandler {
    private static long IMAGE_SIZE_ALLOWED=50000000L;
    private static int IN_MEMEORY_SIZE=50000000;
    
    static private Log log = LogFactory.getLog(FileUploadHandler.class.getName());
    Class clazz;

    public FileUploadHandler(Class clazz) {
        this.clazz = clazz;
    }

    public void crawleDir(String fromDir, String toDir, SessionUser user) {
        File file = new File(fromDir);

        if (file.isDirectory()) {
            crawleDir(file, fromDir, toDir, user);
        }
    }

    /**
     * Receives file from Http.
     *
     * @param ctx calling context.
     * @param req Servlet request.
     * @param fd file location to sae the file.
     */


    public void receive(WebContext ctx, HttpServletRequest req, FileDirectory fd) {
        // Create a factory for disk-based file items
        DiskFileItemFactory factory = new DiskFileItemFactory();

        // Set factory constraints
        String tmpName = ctx.getWebTop() + File.separator + Config.WEB_INF + File.separator + "tmp";

        // the location for saving data that is larger than getSizeThreshold()
        File f = new File(tmpName);

        if (!f.exists()) {
            f.mkdirs();
        }

        factory.setSizeThreshold(IN_MEMEORY_SIZE);
        factory.setRepository(f);

        // Create a new file upload handler
        ServletFileUpload upload = new ServletFileUpload(factory);

        // Set overall request size constraint
        upload.setSizeMax(IMAGE_SIZE_ALLOWED);

        // Parse the request
        List fileItems = null;

        try {
            fileItems = upload.parseRequest(req);
        } catch (Throwable e) {
            e.printStackTrace();
            ctx.addErrorMessage(this, "Failed to upload files due to " + e.getMessage());

            if (log.isErrorEnabled()) {
                log.error(this, e);
            }

            return;
        }

        String category = null;
        String comment = null;
        String access = null;
        Iterator iter = fileItems.iterator();

        while (iter.hasNext()) {
            FileItem fi = (FileItem) iter.next();

            if ("category".equals(fi.getFieldName())) {
                category = fi.getString();
                fi.delete();
            }

            if ("comment".equals(fi.getFieldName())) {
                comment = fi.getString();
                fi.delete();
            }

            if ("access".equals(fi.getFieldName())) {
                access = fi.getString();
                fi.delete();
            }
        }

        //location to save the original
        String imgTop = ctx.getSession().getPersonalContentTop();

        //relative from top
        String fdFullName = "users/" + ctx.getSession().getUser().getId();
        String fdPath = ctx.getSession().getPersonalWebTop();

        //location to save the original
        if (fd != null) {
            imgTop = fd.getFile().getOriginalPath(ctx);

            //where the web top will be saved
            fdPath = fd.getFile().getFile().getPath();

            //relative from top
            fdFullName = fd.getFile().getFullPath();
        }

        //save orig
        Map files = saveFile(fileItems, imgTop);

        //
        List fileNodes = createFileNodes(files, imgTop, fdFullName, ctx.getSession().getUser());

        for (int i = 0; i < fileNodes.size(); i++) {
            FileNode fn = (FileNode) fileNodes.get(i);

            fn.setDescription(comment);

            if (access != null) {
                fn.setAccess(Integer.valueOf(access).intValue());
            } else {
                fn.setAccess(FileNode.PUBLIC);
            }

            fn.setCategory(category);
        }

        processFile(ctx, fileNodes, fdPath);
    }

    private void crawleDir(File file, String fromDir, String toDir, SessionUser user) {
        File[] files = file.listFiles(new FileFilter() {
                    public boolean accept(File pathName) {
                        return pathName.isDirectory() || pathName.getPath().toUpperCase().endsWith("JPG");
                    }
                });

        Map fileMap = new HashMap();

        for (int i = 0; i < files.length; i++) {
            if (files[i].isFile()) {
                fileMap.put(files[i].getName(), files[i].getName());
            } else {
                crawleDir(files[i], fromDir, toDir, user);
            }
        }

        try {
            String destDir = "users/" + user;
            String fdFullName = destDir;

            fdFullName = fdFullName.replace('\\', '/');
            fdFullName = fdFullName.replaceAll("%20", " ");

            List fileNodes = createFileNodes(fileMap, file.getPath(), fdFullName, user);
            processFile(new WebContext(), fileNodes, toDir + File.separator + fdFullName);
        } catch (Exception e) {
            //
        }
    }

    private List createFileNodes(Map fileItems, String imgTop, String fdFullName, SessionUser user) {
        Iterator i = fileItems.keySet().iterator();
        List fileNodes = new ArrayList();

        while (i.hasNext()) {
            String fileName = (String) i.next();
            String genFileName = imgTop + File.separator + fileName;

            FileNode fn = FileNode.createFileNode(clazz.getName());

            fn.setFileLocation(fdFullName);

            String ext = fileName.substring(fileName.lastIndexOf(".") + 1);

            fn.setName(fileName);

            fn.setLink(genFileName);

            fn.setTitle(fileName);

            fn.setAuthorId(user.getId());
            fn.setAuthor(user.getScreenName());
            fileNodes.add(fn);
        }

        return fileNodes;
    }

    //we should defer this
    private void processFile(WebContext ctx, List fileNodes, String topLocation) {
        Iterator iter = fileNodes.iterator();
        
        Meter.start();

        while (iter.hasNext()) {
            FileNode fn = (FileNode) iter.next();
            fn.process(ctx, topLocation);
        }

        Meter.stop("spend in process image");
    }

    private Map saveFile(List fileItems, String imgTop) {
        if (log.isDebugEnabled()) {
            log.debug("Save uploaded file");
        }

        Iterator i = fileItems.iterator();
        Map files = new HashMap();

        while (i.hasNext()) {
            FileItem fi = (FileItem) i.next();
            String fileName = fi.getName();

            if (!fi.isFormField() && (fileName != null) && (fileName.length() != 0)) {
                int index = -1;

                index = fileName.lastIndexOf(File.separator) + 1;

                String saveAs = fileName.substring(index);

                index = saveAs.lastIndexOf("\\") + 1;

                if (index > 0) {
                    saveAs = saveAs.substring(index);
                }

                File imgDir = new File(imgTop);

                if (!imgDir.exists()) {
                    imgDir.mkdirs();
                }

                String genFileName = imgTop + File.separator + saveAs;

                try {
                    fi.write(new File(genFileName));
                    files.put(saveAs, genFileName);
                } catch (Exception e) {
                    System.err.println("Failed to write to " + genFileName);

                    continue;
                } finally {
                    fi.delete();
                }
            } else {
                fi.delete();
            }
        }

        if (log.isDebugEnabled()) {
            log.debug("Done save uploaded file");
        }

        return files;
    }
}
